﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OpenPasteSpider.projectmodel;
using Volo.Abp.ObjectMapping;
using Z.EntityFramework.Plus;

namespace OpenPasteSpider
{
    /// <summary>
    /// 集群模式 master的选举 node状态的变更 内部通知的归总notice
    /// </summary>
    public class SlaveHostedService : IHostedService
    {

        /// <summary>
        /// 
        /// </summary>
        private IServiceProvider _serviceProvider;

        private Random _random;

        //private SlaveHelper _slaveHelper;
        ///// <summary>
        ///// 
        ///// </summary>
        //private AssemblyLoadContext context;
        private ILogger<SlaveHostedService> _logger;

        /// <summary>
        /// 队列状态等
        /// </summary>
        private IObjectMapper _objectMapper;
        private ChannelHelper _channelHelper;

        private SpiderConfig _config;

        /// <summary>
        /// 用于监听任务，需要监听任务
        /// </summary>
        private readonly CommandTaskHandler _commandHandler;

        ///// <summary>
        ///// 用于监听运行状态，统计运行状态，监测运行熟练，需要定时器 和监听队列
        ///// </summary>
        //private readonly StatusTaskHandler _statustaskHandler;

        private readonly RecoveryTaskHandler _recoveryTaskHandler;

        private readonly NoticeTaskHanlder _noticeHanlder;

        /// <summary>
        /// 系统初始化或者检测升级
        /// </summary>
        private readonly InitUpdateHandler _systemInitAndUpdateHandler;

        private readonly LinkHelper _linkHelper;

        private readonly PublicModelHelper _modelHelper;

        private readonly StatusTaskHandler _statustaskHandler;


        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceProvider"></param>
        /// <param name="logger"></param>
        /// <param name="objectMapper"></param>
        /// <param name="channelHelper"></param>
        /// <param name="config"></param>
        /// <param name="recoveryTaskHandler"></param>
        /// <param name="systemInitAndUpdateHandler"></param>
        /// <param name="noticeHanlder"></param>
        /// <param name="commandTaskHandler"></param>
        /// <param name="modelCacheHelper"></param>
        /// <param name="linkHelper"></param>
        /// <param name="appCacheHelper"></param>
        public SlaveHostedService(
            IServiceProvider serviceProvider,
            ILogger<SlaveHostedService> logger,
            IObjectMapper objectMapper,
            ChannelHelper channelHelper,
            IOptions<SpiderConfig> config,
            RecoveryTaskHandler recoveryTaskHandler,
            InitUpdateHandler systemInitAndUpdateHandler,
            NoticeTaskHanlder noticeHanlder,
            CommandTaskHandler commandTaskHandler,
            PublicModelHelper modelCacheHelper,
            LinkHelper linkHelper,
            ICacheHelper appCacheHelper,
            StatusTaskHandler statusTaskHandler
            )
        {
            _serviceProvider = serviceProvider;
            _logger = logger;
            _objectMapper = objectMapper;
            _channelHelper = channelHelper;
            _random = new Random();
            _config = config.Value;
            _linkHelper = linkHelper;
            _recoveryTaskHandler = recoveryTaskHandler;
            _systemInitAndUpdateHandler = systemInitAndUpdateHandler;
            _commandHandler = commandTaskHandler;
            _modelHelper = modelCacheHelper;
            _noticeHanlder = noticeHanlder;
            _statustaskHandler = statusTaskHandler;
        }

        private List<SlaveNodeItem> _nodelist;

        /// <summary>
        /// slave健康检查计时器
        /// </summary>
        private System.Timers.Timer _timerhealth;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            Console.WriteLine($"{DateTime.Now} SlaveHostedService Start! MachineName:{Environment.MachineName}");
            //_tasklist = new List<TaskInfoDto>();
            _nodelist = new List<SlaveNodeItem>();


            using var scop = _serviceProvider.CreateScope();
            using var _dbContext = scop.ServiceProvider.GetRequiredService<IOpenPasteSpiderDbContext>();

            //检查是否有升级
            await _systemInitAndUpdateHandler.DoInitAndUpdateAsync(_dbContext);

            //处理最后一次未处理的任务
            await _commandHandler.DoUnFinishPlanAsync(_dbContext, "");
            
            //集群心跳包监测
            _timerhealth = new System.Timers.Timer();
            _timerhealth.Interval = 1000;
            _timerhealth.Elapsed += _timerhealth_Elapsed;
            _timerhealth.AutoReset = true;
            _timerhealth.Start();

            ReadCommandChannel();

            ReadChannelNotice();

            _logger.LogWarning("System.SlaveHostService Start!");
        }

        /// <summary>
        /// 处理队列中的命令
        /// </summary>
        private async void ReadCommandChannel()
        {
            try
            {
                var info = await _channelHelper.CommandPlanChannel.Reader.ReadAsync();
                if (info != null && info != default)
                {
                    await _commandHandler.DoCommandPlanAsync(info.planid);
                }
            }
            catch (Exception exl)
            {
                _logger.LogException(exl);
                await Task.Delay(1000);
            }
            finally
            {
                ReadCommandChannel();
            }
        }

        ///// <summary>
        ///// 监听状态的变更 
        ///// </summary>
        //private async void ReadChannelState()
        //{
        //    try
        //    {
        //        //node1 ---linux.id=2--->master

        //        var info = await _channelHelper.ChannelMonitor.Reader.ReadAsync();
        //        if (info != null && info != default)
        //        {
        //           await _statustaskHandler.DoChannelMessage(info);
        //        }
        //    }
        //    catch (Exception exl)
        //    {
        //        _logger.LogException(exl);
        //        await Task.Delay(1000);
        //    }
        //    finally
        //    {
        //        ReadChannelState();
        //    }
        //}


        /// <summary>
        /// 读取队列中的消息，消息通知 节点通知给master就行了，最终由master统一处理
        /// </summary>
        private async void ReadChannelNotice()
        {
            try
            {
                var info = await _channelHelper.ChannelNotice.Reader.ReadAsync();
                if (info != null && info != default)
                {
                    _logger.LogWarning(Newtonsoft.Json.JsonConvert.SerializeObject(info));
                    await _noticeHanlder.DoSendNoticeAsync(info);
                }
            }
            catch (Exception exl)
            {
                _logger.LogException(exl);
                await Task.Delay(1000);
            }
            finally
            {
                ReadChannelNotice();
            }
        }

        /// <summary>
        /// 为linux更换节点
        /// </summary>
        /// <param name="_dbContext"></param>
        /// <param name="linuxid"></param>
        /// <param name="slavename"></param>
        private async Task<bool> UpdateLinuxInfo(IOpenPasteSpiderDbContext _dbContext, int linuxid, string slavename)
        {
            //using var _scope = _serviceProvider.CreateScope();
            //using var _dbContext = _scope.ServiceProvider.GetRequiredService<IOpenPasteSpiderDbContext>();
            _dbContext.LinuxInfo.Where(x => x.Id == linuxid).Update(x => new LinuxInfo { SlaveName = slavename });

            await _modelHelper.ItemLinuxClean(linuxid);
            return true;
        }

        /// <summary>
        /// 集群心跳包监测
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _timerhealth_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            var now = DateTime.Now;

            var second = now.ToUnixTimeSeconds();

            var timestr = now.ToString("yyyy-MM-dd HH:mm:ss");

            //凌晨3点进行资源回收
            if (timestr.EndsWith("03:00:00"))
            {

                _recoveryTaskHandler.DoRecoveryAsync();

            }
            //每隔5分钟收集各个状态数据
            if (second % 300 == 0)
            {
                _statustaskHandler.DoReadStatsAsync(null, null);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task StopAsync(CancellationToken cancellationToken)
        {
            //throw new NotImplementedException();
            return Task.CompletedTask;
        }

     

    }
}
